<script lang="ts" setup>
  import { ref, watch } from 'vue';

  interface Props {
    modelValue: string | File;
    accept?: string;
  }
  // 使用泛型约束 props
  const props = withDefaults(defineProps<Props>(), {
    accept: 'image/png, image/jpeg, image/jpg, image/gif, image/webp',
  });
  // 使用泛型约束 emits,
  const emit = defineEmits<{
    (e: 'update:modelValue', val: File): void;
  }>();

  // ref: src => Ref<string>
  const src = ref(props.modelValue as string);
  // template ref: file => Ref(HTMLInputElement | undefined)
  const file = ref<HTMLInputElement>();
  // watch
  watch(
    () => props.modelValue,
    (val) => {
      src.value = val as string;
      file.value!.value = '';
    }
  );
  // methods
  const handleChange = (e: Event) => {
    // 是否选中文件
    const files = (e.target as HTMLInputElement).files;
    // 真值收窄
    if (!files || files.length === 0) {
      return;
    }
    // 读取本地图片并显示
    const reader = new FileReader(),
      file = files[0];
    reader.readAsDataURL(file);
    reader.onload = () => {
      src.value = reader.result as string;
    };
    // 触发事件 update:modelValue 传递文件
    emit('update:modelValue', file);
  };
</script>
<template>
  <div
    class="w-24 h-24 rounded-full border-2 shadow-lg overflow-hidden cursor-pointer"
    @click="file?.click()"
  >
    <input ref="file" type="file" class="hidden" :accept="accept" @change="handleChange" />

    <img class="w-full h-full object-cover" :src="src" v-if="src" />
    <slot v-else>
      <svg
        class="p-2"
        fill="none"
        stroke="currentColor"
        stroke-width="1.5"
        viewBox="0 0 24 24"
        xmlns="http://www.w3.org/2000/svg"
        aria-hidden="true"
      >
        <path
          stroke-linecap="round"
          stroke-linejoin="round"
          d="M15.75 6a3.75 3.75 0 11-7.5 0 3.75 3.75 0 017.5 0zM4.501 20.118a7.5 7.5 0 0114.998 0A17.933 17.933 0 0112 21.75c-2.676 0-5.216-.584-7.499-1.632z"
        />
      </svg>
    </slot>
  </div>
</template>
